home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / shells / tcshsrc.zoo / tcsh / tc.func.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-02-21  |  30.4 KB  |  1,294 lines

  1. /* $Header: /home/hyperion/mu/christos/src/sys/tcsh-6.00/RCS/tc.func.c,v 3.5 1991/07/17 13:21:49 christos Exp $ */
  2. /*
  3.  * tc.func.c: New tcsh builtins.
  4.  */
  5. /*-
  6.  * Copyright (c) 1980, 1991 The Regents of the University of California.
  7.  * All rights reserved.
  8.  *
  9.  * Redistribution and use in source and binary forms, with or without
  10.  * modification, are permitted provided that the following conditions
  11.  * are met:
  12.  * 1. Redistributions of source code must retain the above copyright
  13.  *    notice, this list of conditions and the following disclaimer.
  14.  * 2. Redistributions in binary form must reproduce the above copyright
  15.  *    notice, this list of conditions and the following disclaimer in the
  16.  *    documentation and/or other materials provided with the distribution.
  17.  * 3. All advertising materials mentioning features or use of this software
  18.  *    must display the following acknowledgement:
  19.  *    This product includes software developed by the University of
  20.  *    California, Berkeley and its contributors.
  21.  * 4. Neither the name of the University nor the names of its contributors
  22.  *    may be used to endorse or promote products derived from this software
  23.  *    without specific prior written permission.
  24.  *
  25.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  26.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  27.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  28.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  29.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  30.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  31.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  32.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  33.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  34.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  35.  * SUCH DAMAGE.
  36.  */
  37. #include "config.h"
  38. RCSID("$Id: tc.func.c,v 3.5 1991/07/17 13:21:49 christos Exp $")
  39.  
  40. #include "sh.h"
  41. #include "ed.h"
  42. #include "ed.defns.h"        /* for the function names */
  43. #include "tw.h"
  44. #include "tc.h"
  45.  
  46. extern time_t t_period;
  47. extern int do_logout;
  48. static bool precmd_active = 0;
  49. static bool periodic_active = 0;
  50. static bool cwdcmd_active = 0;    /* PWP: for cwd_cmd */
  51. static bool beepcmd_active = 0;
  52.  
  53. static    void    Reverse        __P((Char *));
  54. static    void    auto_logout    __P((void));
  55. static    void    insert        __P((struct wordent *, bool));
  56. static    void    insert_we    __P((struct wordent *, struct wordent *));
  57. static    int    inlist        __P((Char *, Char *));
  58.  
  59.  
  60. /*
  61.  * Tops-C shell
  62.  */
  63.  
  64. /*
  65.  * expand_lex: Take the given lex and put an expanded version of it in the
  66.  * string buf. First guy in lex list is ignored; last guy is ^J which we
  67.  * ignore Only take lex'es from position from to position to inclusive Note:
  68.  * csh sometimes sets bit 8 in characters which causes all kinds of problems
  69.  * if we don't mask it here. Note: excl's in lexes have been un-back-slashed
  70.  * and must be re-back-slashed
  71.  * (PWP: NOTE: this returns a pointer to the END of the string expanded
  72.  *             (in other words, where the NUL is).)
  73.  */
  74. /* PWP: this is a combination of the old sprlex() and the expand_lex from
  75.    the magic-space stuff */
  76.  
  77. Char   *
  78. expand_lex(buf, bufsiz, sp0, from, to)
  79.     Char   *buf;
  80.     int     bufsiz;
  81.     struct wordent *sp0;
  82.     int     from, to;
  83. {
  84.     register struct wordent *sp;
  85.     register Char *s, *d, *e;
  86.     register Char prev_c;
  87.     register int i;
  88.  
  89.     buf[0] = '\0';
  90.     prev_c = '\0';
  91.     d = buf;
  92.     e = &buf[bufsiz];        /* for bounds checking */
  93.  
  94.     if (!sp0)
  95.     return (buf);        /* null lex */
  96.     if ((sp = sp0->next) == sp0)
  97.     return (buf);        /* nada */
  98.     if (sp == (sp0 = sp0->prev))
  99.     return (buf);        /* nada */
  100.  
  101.     for (i = 0; i < NCARGS; i++) {
  102.     if ((i >= from) && (i <= to)) {    /* if in range */
  103.         for (s = sp->word; *s && d < e; s++) {
  104.         /*
  105.          * bugfix by Michael Bloom: anything but the current history
  106.          * character {(PWP) and backslash} seem to be dealt with
  107.          * elsewhere.
  108.          */
  109.         if ((*s & QUOTE)
  110.             && (((*s & TRIM) == HIST) ||
  111.             ((*s & TRIM) == '\\') && (prev_c != '\\'))) {
  112.             *d++ = '\\';
  113.         }
  114.         *d++ = (*s & TRIM);
  115.         prev_c = *s;
  116.         }
  117.         if (d < e)
  118.         *d++ = ' ';
  119.     }
  120.     sp = sp->next;
  121.     if (sp == sp0)
  122.         break;
  123.     }
  124.     if (d > buf)
  125.     d--;            /* get rid of trailing space */
  126.  
  127.     return (d);
  128. }
  129.  
  130. Char   *
  131. sprlex(buf, sp0)
  132.     Char   *buf;
  133.     struct wordent *sp0;
  134. {
  135.     Char   *cp;
  136.  
  137.     cp = expand_lex(buf, INBUFSIZ, sp0, 0, NCARGS);
  138.     *cp = '\0';
  139.     return (buf);
  140. }
  141.  
  142. void
  143. Itoa(n, s)            /* convert n to characters in s */
  144.     int     n;
  145.     Char   *s;
  146. {
  147.     int     i, sign;
  148.  
  149.     if ((sign = n) < 0)        /* record sign */
  150.     n = -n;
  151.     i = 0;
  152.     do {
  153.     s[i++] = n % 10 + '0';
  154.     } while ((n /= 10) > 0);
  155.     if (sign < 0)
  156.     s[i++] = '-';
  157.     s[i] = '\0';
  158.     Reverse(s);
  159. }
  160.  
  161. static void
  162. Reverse(s)
  163.     Char   *s;
  164. {
  165.     int     c, i, j;
  166.  
  167.     for (i = 0, j = Strlen(s) - 1; i < j; i++, j--) {
  168.     c = s[i];
  169.     s[i] = s[j];
  170.     s[j] = c;
  171.     }
  172. }
  173.  
  174.  
  175. /*ARGSUSED*/
  176. void
  177. dolist(v, c)
  178.     register Char **v;
  179.     struct command *c;
  180. {
  181.     int     i, k;
  182.     struct stat st;
  183.  
  184.     if (*++v == NULL) {
  185.     (void) t_search(STRNULL, NULL, LIST, 0, 0, 0);
  186.     return;
  187.     }
  188.     gflag = 0;
  189.     tglob(v);
  190.     if (gflag) {
  191.     v = globall(v);
  192.     if (v == 0)
  193.         stderror(ERR_NAME | ERR_NOMATCH);
  194.     }
  195.     else
  196.     v = gargv = saveblk(v);
  197.     trim(v);
  198.     for (k = 0; v[k] != NULL && v[k][0] != '-'; k++);
  199.     if (v[k]) {
  200.     /*
  201.      * We cannot process a flag therefore we let ls do it right.
  202.      */
  203.     static Char STRls[] =
  204.     {'l', 's', '\0'};
  205.     static Char STRmCF[] =
  206.     {'-', 'C', 'F', '\0'};
  207.     struct command *t;
  208.     struct wordent cmd, *nextword, *lastword;
  209.     Char   *cp;
  210.  
  211. #ifdef BSDSIGS
  212.     sigmask_t omask = 0;
  213.  
  214.     if (setintr)
  215.         omask = sigblock(sigmask(SIGINT)) & ~sigmask(SIGINT);
  216. #else
  217.     sighold(SIGINT);
  218. #endif
  219.     if (seterr) {
  220.         xfree((ptr_t) seterr);
  221.         seterr = NULL;
  222.     }
  223.     cmd.word = STRNULL;
  224.     lastword = &cmd;
  225.     nextword = (struct wordent *) xcalloc(1, sizeof cmd);
  226.     nextword->word = Strsave(STRls);
  227.     lastword->next = nextword;
  228.     nextword->prev = lastword;
  229.     lastword = nextword;
  230.     nextword = (struct wordent *) xcalloc(1, sizeof cmd);
  231.     nextword->word = Strsave(STRmCF);
  232.     lastword->next = nextword;
  233.     nextword->prev = lastword;
  234.     lastword = nextword;
  235.     for (cp = *v; cp; cp = *++v) {
  236.         nextword = (struct wordent *) xcalloc(1, sizeof cmd);
  237.         nextword->word = Strsave(cp);
  238.         lastword->next = nextword;
  239.         nextword->prev = lastword;
  240.         lastword = nextword;
  241.     }
  242.     lastword->next = &cmd;
  243.     cmd.prev = lastword;
  244.  
  245.     /* build a syntax tree for the command. */
  246.     t = syntax(cmd.next, &cmd, 0);
  247.     if (seterr)
  248.         stderror(ERR_OLD);
  249.     /* expand aliases like process() does */
  250.     /* alias(&cmd); */
  251.     /* execute the parse tree. */
  252.     execute(t, tpgrp > 0 ? tpgrp : -1, NULL, NULL);
  253.     /* done. free the lex list and parse tree. */
  254.     freelex(&cmd), freesyn(t);
  255.     if (setintr)
  256. #ifdef BSDSIGS
  257.         (void) sigsetmask(omask);
  258. #else
  259.         (void) sigrelse(SIGINT);
  260. #endif
  261.     }
  262.     else {
  263.     Char   *dp, *tmp, buf[MAXPATHLEN];
  264.  
  265.     for (k = 0, i = 0; v[k] != NULL; k++) {
  266.         tmp = dnormalize(v[k]);
  267.         dp = &tmp[Strlen(tmp) - 1];
  268.         if (*dp == '/' && dp != tmp)
  269. #ifdef apollo
  270.         if (dp != &tmp[1])
  271. #endif
  272.         *dp = '\0';
  273.         if (stat(short2str(tmp), &st) == -1) {
  274.         if (k != i) {
  275.             if (i != 0)
  276.             xputchar('\n');
  277.             print_by_column(STRNULL, &v[i], k - i, FALSE);
  278.         }
  279.         xprintf("%s: %s.\n", short2str(tmp), strerror(errno));
  280.         i = k + 1;
  281.         }
  282.         else if (S_ISDIR(st.st_mode)) {
  283.         Char   *cp;
  284.  
  285.         if (k != i) {
  286.             if (i != 0)
  287.             xputchar('\n');
  288.             print_by_column(STRNULL, &v[i], k - i, FALSE);
  289.         }
  290.         if (k != 0 && v[1] != NULL)
  291.             xputchar('\n');
  292.         xprintf("%s:\n", short2str(tmp));
  293.         for (cp = tmp, dp = buf; *cp; *dp++ = (*cp++ | QUOTE));
  294.         if (dp[-1] != (Char) ('/' | QUOTE))
  295.             *dp++ = '/';
  296.         else 
  297.             dp[-1] &= TRIM;
  298.         *dp = '\0';
  299.         (void) t_search(buf, NULL, LIST, 0, 0, 0);
  300.         i = k + 1;
  301.         }
  302.         xfree((ptr_t) tmp);
  303.     }
  304.     if (k != i) {
  305.         if (i != 0)
  306.         xputchar('\n');
  307.         print_by_column(STRNULL, &v[i], k - i, FALSE);
  308.     }
  309.     }
  310.  
  311.     if (gargv) {
  312.     blkfree(gargv);
  313.     gargv = 0;
  314.     }
  315. }
  316.  
  317. static char *defaulttell = "ALL";
  318. extern bool GotTermCaps;
  319.  
  320. /*ARGSUSED*/
  321. void
  322. dotelltc(v, c)
  323.     register Char **v;
  324.     struct command *c;
  325. {
  326.  
  327.     if (!GotTermCaps)
  328.     GetTermCaps();
  329.  
  330.     TellTC(v[1] ? short2str(v[1]) : defaulttell);
  331. }
  332.  
  333. /*ARGSUSED*/
  334. void
  335. doechotc(v, c)
  336.     register Char **v;
  337.     struct command *c;
  338. {
  339.     if (!GotTermCaps)
  340.     GetTermCaps();
  341.     EchoTC(++v);
  342. }
  343.  
  344. /*ARGSUSED*/
  345. void
  346. dosettc(v, c)
  347.     Char  **v;
  348.     struct command *c;
  349. {
  350.     char    tv[2][BUFSIZ];
  351.  
  352.     if (!GotTermCaps)
  353.     GetTermCaps();
  354.  
  355.     (void) strcpy(tv[0], short2str(v[1]));
  356.     (void) strcpy(tv[1], short2str(v[2]));
  357.     SetTC(tv[0], tv[1]);
  358. }
  359.  
  360. /* The dowhich() is by:
  361.  *  Andreas Luik <luik@isaak.isa.de>
  362.  *  I S A  GmbH - Informationssysteme fuer computerintegrierte Automatisierung
  363.  *  Azenberstr. 35
  364.  *  D-7000 Stuttgart 1
  365.  *  West-Germany
  366.  * Thanks!!
  367.  */
  368.  
  369. /*ARGSUSED*/
  370. void
  371. dowhich(v, c)
  372.     register Char **v;
  373.     struct command *c;
  374. {
  375.     struct wordent lex[3];
  376.     struct varent *vp;
  377.  
  378.     lex[0].next = &lex[1];
  379.     lex[1].next = &lex[2];
  380.     lex[2].next = &lex[0];
  381.  
  382.     lex[0].prev = &lex[2];
  383.     lex[1].prev = &lex[0];
  384.     lex[2].prev = &lex[1];
  385.  
  386.     lex[0].word = STRNULL;
  387.     lex[2].word = STRret;
  388.  
  389.     while (*++v) {
  390.     if (vp = adrof1(*v, &aliases)) {
  391.         xprintf("%s: \t aliased to ", short2str(*v));
  392.         blkpr(vp->vec);
  393.         xprintf("\n");
  394.     }
  395.     else {
  396.         lex[1].word = *v;
  397.         tellmewhat(lex);
  398.     }
  399.     }
  400. }
  401.  
  402. /* PWP: a hack to start up your stopped editor on a single keystroke */
  403. /* jbs - fixed hack so it worked :-) 3/28/89 */
  404.  
  405. struct process *
  406. find_stop_ed()
  407. {
  408.     register struct process *pp;
  409.     register char *ep, *vp, *p;
  410.     int     epl, vpl;
  411.  
  412.     if ((ep = getenv("EDITOR")) != NULL) {    /* if we have a value */
  413.     if ((p = strrchr(ep, '/')) != NULL) {    /* if it has a path */
  414.         ep = p + 1;        /* then we want only the last part */
  415.     }
  416.     }
  417.     else {
  418.     ep = "ed";
  419.     }
  420.     if ((vp = getenv("VISUAL")) != NULL) {    /* if we have a value */
  421.     if ((p = strrchr(vp, '/')) != NULL) {    /* and it has a path */
  422.         vp = p + 1;        /* then we want only the last part */
  423.     }
  424.     }
  425.     else {
  426.     vp = "vi";
  427.     }
  428.     vpl = strlen(vp);
  429.     epl = strlen(ep);
  430.  
  431.     if (pcurrent == PNULL)    /* see if we have any jobs */
  432.     return PNULL;        /* nope */
  433.  
  434.     for (pp = proclist.p_next; pp; pp = pp->p_next) {
  435.     if (pp->p_pid == pp->p_jobid) {
  436.         p = short2str(pp->p_command);
  437.         /* if we find either in the current name, fg it */
  438.         if (strncmp(ep, p, (size_t) epl) == 0 ||
  439.         strncmp(vp, p, (size_t) vpl) == 0)
  440.         return pp;
  441.     }
  442.     }
  443.     return PNULL;        /* didn't find a job */
  444. }
  445.  
  446. void
  447. fg_proc_entry(pp)
  448.     register struct process *pp;
  449. {
  450. #ifdef BSDSIGS
  451.     sigmask_t omask;
  452. #endif
  453.     jmp_buf osetexit;
  454.     bool    ohaderr;
  455.  
  456.     getexit(osetexit);
  457.  
  458. #ifdef BSDSIGS
  459.     omask = sigblock(sigmask(SIGINT));
  460. #else
  461.     (void) sighold(SIGINT);
  462. #endif
  463.  
  464.     ohaderr = haderr;        /* we need to ignore setting of haderr due to
  465.                  * process getting stopped by a signal */
  466.     if (setexit() == 0) {    /* come back here after pjwait */
  467.     pendjob();
  468.     pstart(pp, 1);        /* found it. */
  469.     pjwait(pp);
  470.     }
  471.  
  472.     resexit(osetexit);
  473.     haderr = ohaderr;
  474.  
  475. #ifdef BSDSIGS
  476.     (void) sigsetmask(omask);
  477. #else
  478.     (void) sigrelse(SIGINT);
  479. #endif
  480.  
  481. }
  482.  
  483. static void
  484. auto_logout()
  485. {
  486.     xprintf("auto-logout\n");
  487.     /* Don't leave the tty in raw mode */
  488.     if (editing)
  489.     (void) Cookedmode();
  490.     (void) close(SHIN);
  491.     set(STRlogout, Strsave(STRautomatic));
  492.     child = 1;
  493. #ifdef TESLA
  494.     do_logout = 1;
  495. #endif                /* TESLA */
  496.     goodbye(NULL, NULL);
  497. }
  498.  
  499. sigret_t
  500. /*ARGSUSED*/
  501. alrmcatch(snum)
  502. int snum;
  503. {
  504.     time_t  cl, nl;
  505. #if (SVID > 0) && (SVID < 3)
  506.     (void) sigset(SIGALRM, alrmcatch);
  507. #endif /* SVID > 0 && SVID < 3 */
  508.  
  509.     if ((nl = sched_next()) == -1)
  510.     auto_logout();        /* no other possibility - logout */
  511.     (void) time(&cl);
  512.     if (nl <= cl + 1)
  513.     sched_run();
  514.     else
  515.     auto_logout();
  516.     setalarm();
  517. #ifndef SIGVOID
  518.     return (snum);
  519. #endif
  520. }
  521.  
  522. /*
  523.  * Karl Kleinpaste, 21oct1983.
  524.  * Added precmd(), which checks for the alias
  525.  * precmd in aliases.  If it's there, the alias
  526.  * is executed as a command.  This is done
  527.  * after mailchk() and just before print-
  528.  * ing the prompt.  Useful for things like printing
  529.  * one's current directory just before each command.
  530.  */
  531. void
  532. precmd()
  533. {
  534. #ifdef BSDSIGS
  535.     sigmask_t omask;
  536. #endif
  537.  
  538. #ifdef BSDSIGS
  539.     omask = sigblock(sigmask(SIGINT));
  540. #else
  541.     (void) sighold(SIGINT);
  542. #endif
  543.     if (precmd_active) {    /* an error must have been caught */
  544.     aliasrun(2, STRunalias, STRprecmd);
  545.     xprintf("Faulty alias 'precmd' removed.\n");
  546.     goto leave;
  547.     }
  548.     precmd_active = 1;
  549.     if (!whyles && adrof1(STRprecmd, &aliases))
  550.     aliasrun(1, STRprecmd, NULL);
  551. leave:
  552.     precmd_active = 0;
  553. #ifdef BSDSIGS
  554.     (void) sigsetmask(omask);
  555. #else
  556.     (void) sigrelse(SIGINT);
  557. #endif
  558. }
  559.  
  560. /*
  561.  * Paul Placeway  11/24/87  Added cwd_cmd by hacking precmd() into
  562.  * submission...  Run every time $cwd is set (after it is set).  Useful
  563.  * for putting your machine and cwd (or anything else) in an xterm title
  564.  * space.
  565.  */
  566. void
  567. cwd_cmd()
  568. {
  569. #ifdef BSDSIGS
  570.     sigmask_t omask;
  571. #endif
  572.  
  573. #ifdef BSDSIGS
  574.     omask = sigblock(sigmask(SIGINT));
  575. #else
  576.     (void) sighold(SIGINT);
  577. #endif
  578.     if (cwdcmd_active) {    /* an error must have been caught */
  579.     aliasrun(2, STRunalias, STRcwdcmd);
  580.     xprintf("Faulty alias 'cwdcmd' removed.\n");
  581.     goto leave;
  582.     }
  583.     cwdcmd_active = 1;
  584.     if (!whyles && adrof1(STRcwdcmd, &aliases))
  585.     aliasrun(1, STRcwdcmd, NULL);
  586. leave:
  587.     cwdcmd_active = 0;
  588. #ifdef BSDSIGS
  589.     (void) sigsetmask(omask);
  590. #else
  591.     (void) sigrelse(SIGINT);
  592. #endif
  593. }
  594.  
  595. /*
  596.  * Joachim Hoenig  07/16/91  Added beep_cmd, run every time tcsh wishes 
  597.  * to beep the terminal bell. Useful for playing nice sounds instead.
  598.  */
  599. void
  600. beep_cmd()
  601. {
  602. #ifdef BSDSIGS
  603.     sigmask_t omask;
  604. #endif
  605.  
  606. #ifdef BSDSIGS
  607.     omask = sigblock(sigmask(SIGINT));
  608. #else
  609.     (void) sighold(SIGINT);
  610. #endif
  611.     if (beepcmd_active) {    /* an error must have been caught */
  612.     aliasrun(2, STRunalias, STRbeepcmd);
  613.     xprintf("Faulty alias 'beepcmd' removed.\n");
  614.     }
  615.     else {
  616.     beepcmd_active = 1;
  617.     if (!whyles && adrof1(STRbeepcmd, &aliases))
  618.         aliasrun(1, STRbeepcmd, NULL);
  619.     }
  620.     beepcmd_active = 0;
  621. #ifdef BSDSIGS
  622.     (void) sigsetmask(omask);
  623. #else
  624.     (void) sigrelse(SIGINT);
  625. #endif
  626. }
  627.  
  628.  
  629. /*
  630.  * Karl Kleinpaste, 18 Jan 1984.
  631.  * Added period_cmd(), which executes the alias "periodic" every
  632.  * $tperiod minutes.  Useful for occasional checking of msgs and such.
  633.  */
  634. void
  635. period_cmd()
  636. {
  637.     register Char *vp;
  638.     time_t  t, interval;
  639. #ifdef BSDSIGS
  640.     sigmask_t omask;
  641. #endif
  642.  
  643. #ifdef BSDSIGS
  644.     omask = sigblock(sigmask(SIGINT));
  645. #else
  646.     (void) sighold(SIGINT);
  647. #endif
  648.     if (periodic_active) {    /* an error must have been caught */
  649.     aliasrun(2, STRunalias, STRperiodic);
  650.     xprintf("Faulty alias 'periodic' removed.\n");
  651.     goto leave;
  652.     }
  653.     periodic_active = 1;
  654.     if (!whyles && adrof1(STRperiodic, &aliases)) {
  655.     vp = value(STRtperiod);
  656.     if (vp == NOSTR)
  657.         return;
  658.     interval = getn(vp);
  659.     (void) time(&t);
  660.     if (t - t_period >= interval * 60) {
  661.         t_period = t;
  662.         aliasrun(1, STRperiodic, NULL);
  663.     }
  664.     }
  665. leave:
  666.     periodic_active = 0;
  667. #ifdef BSDSIGS
  668.     (void) sigsetmask(omask);
  669. #else
  670.     (void) sigrelse(SIGINT);
  671. #endif
  672. }
  673.  
  674. /*
  675.  * Karl Kleinpaste, 21oct1983.
  676.  * Set up a one-word alias command, for use for special things.
  677.  * This code is based on the mainline of process().
  678.  */
  679. void
  680. aliasrun(cnt, s1, s2)
  681.     int     cnt;
  682.     Char   *s1, *s2;
  683. {
  684.     struct wordent w, *new1, *new2;    /* for holding alias name */
  685.     struct command *t = NULL;
  686.     jmp_buf osetexit;
  687.  
  688.     getexit(osetexit);
  689.     if (seterr) {
  690.     xfree((ptr_t) seterr);
  691.     seterr = NULL;    /* don't repeatedly print err msg. */
  692.     }
  693.     w.word = STRNULL;
  694.     new1 = (struct wordent *) xcalloc(1, sizeof w);
  695.     new1->word = Strsave(s1);
  696.     if (cnt == 1) {
  697.     /* build a lex list with one word. */
  698.     w.next = w.prev = new1;
  699.     new1->next = new1->prev = &w;
  700.     }
  701.     else {
  702.     /* build a lex list with two words. */
  703.     new2 = (struct wordent *) xcalloc(1, sizeof w);
  704.     new2->word = Strsave(s2);
  705.     w.next = new2->prev = new1;
  706.     new1->next = w.prev = new2;
  707.     new1->prev = new2->next = &w;
  708.     }
  709.  
  710.     /* expand aliases like process() does. */
  711.     alias(&w);
  712.     /* build a syntax tree for the command. */
  713.     t = syntax(w.next, &w, 0);
  714.     if (seterr)
  715.     stderror(ERR_OLD);
  716.  
  717.     psavejob();
  718.     /* catch any errors here */
  719.     if (setexit() == 0)
  720.     /* execute the parse tree. */
  721.     /*
  722.      * From: Michael Schroeder <mlschroe@immd4.informatik.uni-erlangen.de>
  723.      * was execute(t, tpgrp);
  724.      */
  725.     execute(t, tpgrp > 0 ? tpgrp : -1, NULL, NULL);    
  726.     /* done. free the lex list and parse tree. */
  727.     freelex(&w), freesyn(t);
  728.     if (haderr) {
  729.     haderr = 0;
  730.     /*
  731.      * Either precmd, or cwdcmd, or periodic had an error. Call it again so
  732.      * that it is removed
  733.      */
  734.     if (precmd_active)
  735.         precmd();
  736. #ifdef notdef
  737.     /*
  738.      * XXX: On the other hand, just interrupting them causes an error too.
  739.      * So if we hit ^C in the middle of cwdcmd or periodic the alias gets
  740.      * removed. We don't want that. Note that we want to remove precmd
  741.      * though, cause that could lead into an infinite loop. This should be
  742.      * fixed correctly, but then haderr should give us the whole exit
  743.      * status not just true or false.
  744.      */
  745.     else if (cwdcmd_active)
  746.         cwd_cmd();
  747.     else if (beepcmd_active)
  748.         beep_cmd();
  749.     else if (periodic_active)
  750.         period_cmd();
  751. #endif
  752.     }
  753.     /* reset the error catcher to the old place */
  754.     resexit(osetexit);
  755.     prestjob();
  756.     pendjob();
  757. }
  758.  
  759. void
  760. setalarm()
  761. {
  762.     struct varent *vp;
  763.     Char   *cp;
  764.     unsigned alrm_time = 0;
  765.     time_t cl, nl, sched_dif;
  766.  
  767.     if (vp = adrof(STRautologout)) {
  768.     if (cp = vp->vec[0])
  769.         alrm_time = (atoi(short2str(cp)) * 60);
  770.     }
  771.     if ((nl = sched_next()) != -1) {
  772.     (void) time(&cl);
  773.     sched_dif = nl - cl;
  774.     if ((alrm_time == 0) || (sched_dif < alrm_time))
  775.         alrm_time = ((int) sched_dif) + 1;
  776.     }
  777.     (void) alarm(alrm_time);    /* Autologout ON */
  778. }
  779.  
  780. #define RMDEBUG            /* For now... */
  781.  
  782. void
  783. rmstar(cp)
  784.     struct wordent *cp;
  785. {
  786.     struct wordent *we, *args;
  787.     register struct wordent *tmp, *del;
  788.  
  789. #ifdef RMDEBUG
  790.     static Char STRrmdebug[] =
  791.     {'r', 'm', 'd', 'e', 'b', 'u', 'g', '\0'};
  792.     Char   *tag;
  793.  
  794. #endif
  795.     Char   *charac;
  796.     char    c;
  797.     int     ask, doit, star = 0, silent = 0;
  798.  
  799.     if (!adrof(STRrmstar))
  800.     return;
  801. #ifdef RMDEBUG
  802.     tag = value(STRrmdebug);
  803. #endif
  804.     we = cp->next;
  805.     while (*we->word == ';' && we != cp)
  806.     we = we->next;
  807.     while (we != cp) {
  808. #ifdef RMDEBUG
  809.     if (*tag)
  810.         xprintf("parsing command line\n");
  811. #endif
  812.     if (!Strcmp(we->word, STRrm)) {
  813.         args = we->next;
  814.         ask = (*args->word != '-');
  815.         while (*args->word == '-' && !silent) {    /* check options */
  816.         for (charac = (args->word + 1); *charac && !silent; charac++)
  817.             silent = (*charac == 'i' || *charac == 'f');
  818.         args = args->next;
  819.         }
  820.         ask = (ask || !ask && !silent);
  821.         if (ask) {
  822.         for (; !star && *args->word != ';'
  823.              && args != cp; args = args->next)
  824.             if (!Strcmp(args->word, STRstar))
  825.             star = 1;
  826.         if (ask && star) {
  827.             xprintf("Do you really want to delete all files? [n/y] ");
  828.             flush();
  829.             (void) read(SHIN, &c, 1);
  830.             doit = (c == 'Y' || c == 'y');
  831.             while (c != '\n')
  832.             (void) read(SHIN, &c, 1);
  833.             if (!doit) {
  834.             /* remove the command instead */
  835.             if (*tag)
  836.                 xprintf("skipping deletion of files!\n");
  837.             for (tmp = we;
  838.                  *tmp->word != '\n' &&
  839.                  *tmp->word != ';' && tmp != cp;) {
  840.                 tmp->prev->next = tmp->next;
  841.                 tmp->next->prev = tmp->prev;
  842.                 xfree((ptr_t) tmp->word);
  843.                 del = tmp;
  844.                 tmp = tmp->next;
  845.                 xfree((ptr_t) del);
  846.             }
  847.             if (*tmp->word == ';') {
  848.                 tmp->prev->next = tmp->next;
  849.                 tmp->next->prev = tmp->prev;
  850.                 xfree((ptr_t) tmp->word);
  851.                 del = tmp;
  852.                 xfree((ptr_t) del);
  853.             }
  854.             }
  855.         }
  856.         }
  857.     }
  858.     for (we = we->next;
  859.          *we->word != ';' && we != cp;
  860.          we = we->next);
  861.     if (*we->word == ';')
  862.         we = we->next;
  863.     }
  864. #ifdef RMDEBUG
  865.     if (*tag) {
  866.     xprintf("command line now is:\n");
  867.     for (we = cp->next; we != cp; we = we->next)
  868.         xprintf("%s ", short2str(we->word));
  869.     }
  870. #endif
  871.     return;
  872. }
  873.  
  874. #ifdef BSDJOBS
  875. /* Check if command is in continue list
  876.    and do a "aliasing" if it exists as a job in background */
  877.  
  878. #define CNDEBUG            /* For now */
  879. void
  880. continue_jobs(cp)
  881.     struct wordent *cp;
  882. {
  883.     struct wordent *we;
  884.     register struct process *pp, *np;
  885.     Char   *cmd, *continue_list, *continue_args_list;
  886.  
  887. #ifdef CNDEBUG
  888.     Char   *tag;
  889.     static Char STRcndebug[] =
  890.     {'c', 'n', 'd', 'e', 'b', 'u', 'g', '\0'};
  891.  
  892. #endif
  893.     bool    in_cont_list, in_cont_arg_list;
  894.  
  895.  
  896. #ifdef CNDEBUG
  897.     tag = value(STRcndebug);
  898. #endif
  899.     continue_list = value(STRcontinue);
  900.     continue_args_list = value(STRcontinue_args);
  901.     if (*continue_list == '\0' && *continue_args_list == '\0')
  902.     return;
  903.  
  904.     we = cp->next;
  905.     while (*we->word == ';' && we != cp)
  906.     we = we->next;
  907.     while (we != cp) {
  908. #ifdef CNDEBUG
  909.     if (*tag)
  910.         xprintf("parsing command line\n");
  911. #endif
  912.     cmd = we->word;
  913.     in_cont_list = inlist(continue_list, cmd);
  914.     in_cont_arg_list = inlist(continue_args_list, cmd);
  915.     if (in_cont_list || in_cont_arg_list) {
  916. #ifdef CNDEBUG
  917.         if (*tag)
  918.         xprintf("in one of the lists\n");
  919. #endif
  920.         np = PNULL;
  921.         for (pp = proclist.p_next; pp; pp = pp->p_next) {
  922.         if (prefix(cmd, pp->p_command)) {
  923.             if (pp->p_index) {
  924.             np = pp;
  925.             break;
  926.             }
  927.         }
  928.         }
  929.         if (np) {
  930.         insert(we, in_cont_arg_list);
  931.         }
  932.     }
  933.     for (we = we->next;
  934.          *we->word != ';' && we != cp;
  935.          we = we->next);
  936.     if (*we->word == ';')
  937.         we = we->next;
  938.     }
  939. #ifdef CNDEBUG
  940.     if (*tag) {
  941.     xprintf("command line now is:\n");
  942.     for (we = cp->next; we != cp; we = we->next)
  943.         xprintf("%s ",
  944.             short2str(we->word));
  945.     }
  946. #endif
  947.     return;
  948. }
  949.  
  950. /* The actual "aliasing" of for backgrounds() is done here
  951.    with the aid of insert_we().   */
  952. static void
  953. insert(plist, file_args)
  954.     struct wordent *plist;
  955.     bool    file_args;
  956. {
  957.     struct wordent *now, *last;
  958.     Char   *cmd, *bcmd, *cp1, *cp2;
  959.     int     cmd_len;
  960.     Char   *pause = STRunderpause;
  961.     int     p_len = Strlen(pause);
  962.  
  963.     cmd_len = Strlen(plist->word);
  964.     cmd = (Char *) xcalloc(1, (size_t) ((cmd_len + 1) * sizeof(Char)));
  965.     (void) Strcpy(cmd, plist->word);
  966. /* Do insertions at beginning, first replace command word */
  967.  
  968.     if (file_args) {
  969.     now = plist;
  970.     xfree((ptr_t) now->word);
  971.     now->word = (Char *) xcalloc(1, (size_t) (5 * sizeof(Char)));
  972.     (void) Strcpy(now->word, STRecho);
  973.  
  974.     now = (struct wordent *) xcalloc(1, (size_t) sizeof(struct wordent));
  975.     now->word = (Char *) xcalloc(1, (size_t) (6 * sizeof(Char)));
  976.     (void) Strcpy(now->word, STRbackqpwd);
  977.     insert_we(now, plist);
  978.  
  979.     for (last = now; *last->word != '\n' && *last->word != ';';
  980.          last = last->next);
  981.  
  982.     now = (struct wordent *) xcalloc(1, (size_t) sizeof(struct wordent));
  983.     now->word = (Char *) xcalloc(1, (size_t) (2 * sizeof(Char)));
  984.     (void) Strcpy(now->word, STRgt);
  985.     insert_we(now, last->prev);
  986.  
  987.     now = (struct wordent *) xcalloc(1, (size_t) sizeof(struct wordent));
  988.     now->word = (Char *) xcalloc(1, (size_t) (2 * sizeof(Char)));
  989.     (void) Strcpy(now->word, STRbang);
  990.     insert_we(now, last->prev);
  991.  
  992.     now = (struct wordent *) xcalloc(1, (size_t) sizeof(struct wordent));
  993.     now->word = (Char *) xcalloc(1, (size_t) cmd_len + p_len + 4);
  994.     cp1 = now->word;
  995.     cp2 = cmd;
  996.     *cp1++ = '~';
  997.     *cp1++ = '/';
  998.     *cp1++ = '.';
  999.     while (*cp1++ = *cp2++);
  1000.     cp1--;
  1001.     cp2 = pause;
  1002.     while (*cp1++ = *cp2++);
  1003.     insert_we(now, last->prev);
  1004.  
  1005.     now = (struct wordent *) xcalloc(1, (size_t) sizeof(struct wordent));
  1006.     now->word = (Char *) xcalloc(1, (size_t) (2 * sizeof(Char)));
  1007.     (void) Strcpy(now->word, STRsemi);
  1008.     insert_we(now, last->prev);
  1009.     bcmd = (Char *) xcalloc(1, (size_t) ((cmd_len + 2) * sizeof(Char)));
  1010.     cp1 = bcmd;
  1011.     cp2 = cmd;
  1012.     *cp1++ = '%';
  1013.     while (*cp1++ = *cp2++);
  1014.     now = (struct wordent *) xcalloc(1, (size_t) (sizeof(struct wordent)));
  1015.     now->word = bcmd;
  1016.     insert_we(now, last->prev);
  1017.     }
  1018.     else {
  1019.     struct wordent *del;
  1020.  
  1021.     now = plist;
  1022.     xfree((ptr_t) now->word);
  1023.     now->word = (Char *) xcalloc(1, (size_t) ((cmd_len + 2) * sizeof(Char)));
  1024.     cp1 = now->word;
  1025.     cp2 = cmd;
  1026.     *cp1++ = '%';
  1027.     while (*cp1++ = *cp2++);
  1028.     for (now = now->next;
  1029.          *now->word != '\n' && *now->word != ';' && now != plist;) {
  1030.         now->prev->next = now->next;
  1031.         now->next->prev = now->prev;
  1032.         xfree((ptr_t) now->word);
  1033.         del = now;
  1034.         now = now->next;
  1035.         xfree((ptr_t) del);
  1036.     }
  1037.     }
  1038. }
  1039.  
  1040. static void
  1041. insert_we(new, where)
  1042.     struct wordent *new, *where;
  1043. {
  1044.  
  1045.     new->prev = where;
  1046.     new->next = where->next;
  1047.     where->next = new;
  1048.     new->next->prev = new;
  1049. }
  1050.  
  1051. static int
  1052. inlist(list, name)
  1053.     Char   *list, *name;
  1054. {
  1055.     register Char *l, *n;
  1056.  
  1057.     l = list;
  1058.     n = name;
  1059.  
  1060.     while (*l && *n) {
  1061.     if (*l == *n) {
  1062.         l++;
  1063.         n++;
  1064.         if (*n == '\0' && (*l == ' ' || *l == '\0'))
  1065.         return (1);
  1066.         else
  1067.         continue;
  1068.     }
  1069.     else {
  1070.         while (*l && *l != ' ')
  1071.         l++;        /* skip to blank */
  1072.         while (*l && *l == ' ')
  1073.         l++;        /* and find first nonblank character */
  1074.         n = name;
  1075.     }
  1076.     }
  1077.     return (0);
  1078. }
  1079.  
  1080. #endif                /* BSDJOBS */
  1081.  
  1082.  
  1083. /*
  1084.  * Implement a small cache for tilde names. This is used primarily
  1085.  * to expand tilde names to directories, but also
  1086.  * we can find users from their home directories for the tilde
  1087.  * prompt, on machines where yp lookup is slow this can be a big win...
  1088.  * As with any cache this can run out of sync, rehash can sync it again.
  1089.  */
  1090. static struct tildecache {
  1091.     Char   *user;
  1092.     Char   *home;
  1093.     int     hlen;
  1094. }      *tcache = NULL;
  1095.  
  1096. #define TILINCR 10
  1097. static int tlength = 0, tsize = TILINCR;
  1098.  
  1099. static int
  1100. tildecompare(p1, p2)
  1101.     struct tildecache *p1, *p2;
  1102. {
  1103.     return Strcmp(p1->user, p2->user);
  1104. }
  1105.  
  1106. Char   *
  1107. gettilde(us)
  1108.     Char   *us;
  1109. {
  1110.     struct tildecache *bp1, *bp2, *bp;
  1111.     register struct passwd *pp;
  1112.  
  1113.     if (tcache == NULL)
  1114.     tcache = (struct tildecache *) xmalloc((size_t) (TILINCR *
  1115.                           sizeof(struct tildecache)));
  1116.     /*
  1117.      * Binary search
  1118.      */
  1119.     for (bp1 = tcache, bp2 = tcache + tlength; bp1 < bp2;) {
  1120.     register int i;
  1121.  
  1122.     bp = bp1 + ((bp2 - bp1) >> 1);
  1123.     if ((i = *us - *bp->user) == 0 && (i = Strcmp(us, bp->user)) == 0)
  1124.         return (bp->home);
  1125.     if (i < 0)
  1126.         bp2 = bp;
  1127.     else
  1128.         bp1 = bp + 1;
  1129.     }
  1130.     /*
  1131.      * Not in the cache, try to get it from the passwd file
  1132.      */
  1133.     pp = getpwnam(short2str(us));
  1134. #ifdef YPBUGS
  1135.     fix_yp_bugs();
  1136. #endif
  1137.     if (pp == NULL)
  1138.     return NULL;
  1139.  
  1140.     /*
  1141.      * Update the cache
  1142.      */
  1143.     tcache[tlength].user = Strsave(us);
  1144.     us = tcache[tlength].home = Strsave(str2short(pp->pw_dir));
  1145.     tcache[tlength++].hlen = Strlen(us);
  1146.  
  1147.     (void) qsort((ptr_t) tcache, (size_t) tlength, sizeof(struct tildecache),
  1148.          tildecompare);
  1149.  
  1150.     if (tlength == tsize) {
  1151.     tsize += TILINCR;
  1152.     tcache = (struct tildecache *) xrealloc((ptr_t) tcache,
  1153.                         (size_t) (tsize *
  1154.                           sizeof(struct tildecache)));
  1155.     }
  1156.     return (us);
  1157. }
  1158.  
  1159. /*
  1160.  * Return the username if the directory path passed contains a
  1161.  * user's home directory in the tilde cache, otherwise return NULL
  1162.  * hm points to the place where the path became different.
  1163.  * Special case: Our own home directory.
  1164.  * If we are passed a null pointer, then we flush the cache.
  1165.  */
  1166. Char   *
  1167. getusername(hm)
  1168.     Char  **hm;
  1169. {
  1170.     Char   *h, *p;
  1171.     int     i, j;
  1172.  
  1173.     if (hm == NULL) {
  1174.     for (i = 0; i < tlength; i++) {
  1175.         xfree((ptr_t) tcache[i].home);
  1176.         xfree((ptr_t) tcache[i].user);
  1177.     }
  1178.     xfree((ptr_t) tcache);
  1179.     tlength = 0;
  1180.     tsize = TILINCR;
  1181.     tcache = NULL;
  1182.     return NULL;
  1183.     }
  1184.     if (((h = value(STRhome)) != NULL) &&
  1185.     (Strncmp(p = *hm, h, j = Strlen(h)) == 0) &&
  1186.     (p[j] == '/' || p[j] == '\0')) {
  1187.     *hm = &p[j];
  1188.     return STRNULL;
  1189.     }
  1190.     for (i = 0; i < tlength; i++)
  1191.     if ((Strncmp(p = *hm, tcache[i].home, j = tcache[i].hlen) == 0) &&
  1192.         (p[j] == '/' || p[j] == '\0')) {
  1193.         *hm = &p[j];
  1194.         return tcache[i].user;
  1195.     }
  1196.     return NULL;
  1197. }
  1198.  
  1199. /*
  1200.  * PWP: read a bunch of aliases out of a file QUICKLY.  The format
  1201.  *  is almost the same as the result of saying "alias > FILE", except
  1202.  *  that saying "aliases > FILE" does not expand non-letters to printable
  1203.  *  sequences.
  1204.  */
  1205. /*ARGSUSED*/
  1206. void
  1207. doaliases(v, c)
  1208.     Char  **v;
  1209.     struct command *c;
  1210. {
  1211.     jmp_buf oldexit;
  1212.     Char  **vec, *lp;
  1213.     int     fd;
  1214.     Char    buf[BUFSIZ], line[BUFSIZ];
  1215.     char    tbuf[BUFSIZ + 1], *tmp;
  1216.     extern bool output_raw;    /* PWP: in sh.print.c */
  1217.  
  1218.     v++;
  1219.     if (*v == 0) {
  1220.     output_raw = 1;
  1221.     plist(&aliases);
  1222.     output_raw = 0;
  1223.     return;
  1224.     }
  1225.  
  1226.     gflag = 0, tglob(v);
  1227.     if (gflag) {
  1228.     v = globall(v);
  1229.     if (v == 0)
  1230.         stderror(ERR_NAME | ERR_NOMATCH);
  1231.     }
  1232.     else {
  1233.     v = gargv = saveblk(v);
  1234.     trim(v);
  1235.     }
  1236.  
  1237.     if ((fd = open(tmp = short2str(*v), O_RDONLY)) < 0)
  1238.     stderror(ERR_NAME | ERR_SYSTEM, tmp, strerror(errno));
  1239.  
  1240.     getexit(oldexit);
  1241.     if (setexit() == 0) {
  1242.     for (;;) {
  1243.         Char   *p = NULL;
  1244.         int     n = 0;
  1245.         lp = line;
  1246.         for (;;) {
  1247.         if (n <= 0) {
  1248.             int     i;
  1249.  
  1250.             if ((n = read(fd, tbuf, BUFSIZ)) <= 0)
  1251.             goto eof;
  1252. #ifdef __MINT__
  1253.     /* we probably should strip the carriage returns, but
  1254.      * changing them to blanks will work just as well for most cases
  1255.      */
  1256.             for (i = 0; i < n; i++)
  1257.             buf[i] = (tbuf[i] == '\r') ? ' ' : tbuf[i];
  1258. #else
  1259.             for (i = 0; i < n; i++)
  1260.             buf[i] = tbuf[i];
  1261. #endif
  1262.  
  1263.             p = buf;
  1264.         }
  1265.         n--;
  1266.         if ((*lp++ = *p++) == '\n') {
  1267.             lp[-1] = '\0';
  1268.             break;
  1269.         }
  1270.         }
  1271.         for (lp = line; *lp; lp++) {
  1272.         if (isspc(*lp)) {
  1273.             *lp++ = '\0';
  1274.             while (isspc(*lp))
  1275.             lp++;
  1276.             vec = (Char **) xmalloc((size_t)
  1277.                         (2 * sizeof(Char **)));
  1278.             vec[0] = Strsave(lp);
  1279.             vec[1] = NULL;
  1280.             setq(strip(line), vec, &aliases);
  1281.             break;
  1282.         }
  1283.         }
  1284.     }
  1285.     }
  1286.  
  1287. eof:
  1288.     (void) close(fd);
  1289.     tw_clear_comm_list();
  1290.     if (gargv)
  1291.     blkfree(gargv), gargv = 0;
  1292.     resexit(oldexit);
  1293. }
  1294.